package com.archeocs.figone.lib;

//Author:
//Miłosz Pigłas, Archeocs milosz@archeocs.com
//
//Copyright (c) 2010, Miłosz Pigłas, Archeocs
//
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the distribution.
//* Neither the name of the [ORGANIZATION] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/**
 * Reprezentacja obszaru, na ktorym sa rysowane obrazki w postaci macierzowej
 * @author Milosz Piglas
 */
public class Macierz {
	
	public static int KRAW_DL = 20;
	private int[][] macierz;
	private int mi, mj, num = 1;
	
	public Macierz(int i, int j)
	{
		//System.out.println("i "+i+" j "+j);
		macierz = new int[i][j];
		mi = i;
		mj = j;
	}
	
	/**
	 * tworzy nowa macierz
	 */
	public void zeruj()
    {
       	macierz = new int[mi][mj];
    }
	
	/**
	 * Ustawia wartosc wybranego wspolczynnika na 1
	 * @param i rzad 
	 * @param j kolumna
	 */
	public void setOne(int i, int j)
	{
		macierz[i][j] = 1;
	}
	
	/**
	 * Oznacza wybrany obszar jako zajety (wypelnia wartosciami roznymi od 0)
	 * @param si wspolrzedna lewego gornego naroznika obszaru (rzad)
	 * @param sj wspolrzedna lewego gornego naroznika obszaru (kolumna)
	 * @param sz szerokosc obszaru
	 * @param wy wysokosc obszaru
	 */
	public void setOne(int si, int sj, int sz, int wy) 
	{
		int ei = si+wy-1;
        int ej = sj+sz-1;
      //  System.out.println("si "+si+" ei "+ei);
       // System.out.println("sj "+sj+" ej "+ej);
        for (int i = si; i < ei+1; i++)
        {
            for (int j = sj; j < ej+1; j++)
            	this.macierz[i][j] = this.num;
        }
        this.num++;
	}
	
	/**
	 * Sprawdza, czy w dostepnej przestrzeni znajduje sie wolny obszar do wstawienia obrazka o zadanej szerokosci i wysokosci
	 * @param top wspolrzedna lewego gornego naroznika (rzad)
	 * @param down wspolrzedna lewego dolnego naroznika (rzad)
	 * @param dl szerokosc obrazka
	 * @return wspolrzedna lewego gornego naroznika (kolumna) - ze wspolrzedna top wyznacza poczatek obszaru w ktorym potencjalnie moze zmiescic sie obrazek
	 */
	private int zeroRow(int top, int down, int dl)
    {
        int c_zero = 0,c=0;
        int sj = -1;
        for (int j = 0; j < this.mj; j++)
        {
            if (c_zero == dl)
                return sj;
            else if (c_zero < dl && macierz[top][j] == 0 && macierz[down][j] == 0 )
            {
                if (sj < 0)
                {
                    boolean srod = true;
                    for (int a = top; a < down+1; a++)
                    {
                        if (macierz[a][j] != 0)
                        {
                            srod = false;
                            break;
                        }
                    }
                    if (srod)
                    {
                        sj = j;
                        c_zero++;
                    }
                }
                else
                	c_zero++;
            }
            else if (c_zero < dl && (this.mj - j) > dl && (macierz[top][j] != 0 || macierz[down][j] != 0))
            {
                sj = -1;
                c_zero = 0;
            }
            else 
				return -1;
            c++;
        }
        if (c_zero == dl)
            return sj;
        else
            return -1;
    }
	
	/**
	 * Sprawdza, czy kolumna o wspolrzednych poczatkowych (i, j) i dlugosci dl nie zawiera wspolczynnikow roznych od zero
	 * @param i wspolrzedna poczatkowa kolumny (rzad)
	 * @param j wspolrzedna poczatkowa kolumny (kolumna)
	 * @param dl dluogosc kolumny
	 * @return
	 */
	public boolean zeroCol(int i, int j, int dl)
    {
        int c_zero = 0, c = 0;
        for (int si = i; si < this.mi; si++)
        {
    //      Console.WriteLine("ZC i {0}, j {1}, M (i X j) {2} ",si,j,macierz[si,j]);
            if (c_zero == dl)
               	return true;
            else if (c_zero < dl && macierz[si][j] == 0)
               	c_zero++;
            else if (c_zero < dl && macierz[si][j] != 0)
            	return false;
            c++;
        }
        if (c_zero == dl)
            return true;
        else
            return false;
    }
	
	/**
	 * Wyszukuje wolny obszar o zadanej szerokosci i wysokosci
	 * @param sz szerokosc obrazka (w kwadratach)
	 * @param wy wysokosc obrazka (w kwadratach)
	 * @return wspolrzedne [y,x] lewego gornego naroznika obszaru jesli znaleziono obszar; null jesli nie znaleziono pasujacego obszaru.
	 */
	public int[] getObszar(int sz, int wy)
    {
        int lj, rj, tmp,si = 0;
        while (si < this.mi && (si+wy-1) < this.mi)
        {
            tmp = zeroRow(si,si+wy-1,sz);
            lj = tmp;
            rj = lj+sz-1;
            if (lj >= 0)
            {
                boolean puste = true;
                while (lj <= rj )
                {
                    if (zeroCol(si,lj,wy) && zeroCol(si,rj,wy))
                    {
                        lj++;
                        rj--;
                    }
                    else
                    {
                        puste = false;
                        break;
                    }
                }
                if (puste && tmp >= 0)
                	return new int[]{si,tmp};

            }
            si++;
        }
        return null;
    }

}
